package com.he.interceptor;

import com.alibaba.fastjson2.JSON;
import com.he.annotation.AccessLimit;
import com.he.constant.RedisConstant;
import com.he.domain.Result;
import com.he.enums.StatusCodeEnum;
import com.he.utils.IpUtils;
import com.he.utils.RedisCache;
import com.he.utils.WebUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import jakarta.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author He
 * @version 1.0
 * @Date 2023/9/8 10:14
 * @Desc redis拦截器
 */
@SuppressWarnings("all")
@Component
public class AccessLimitInterceptor implements HandlerInterceptor {

    @Resource
    private RedisCache redisCache;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println(request.getRequestURI());
        boolean result = true;
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            //获取实际被调用的控制器层方法对象
            Method method = handlerMethod.getMethod();
            // 检查方法是否标记了 @AccessLimit 注解
            if (method.isAnnotationPresent(AccessLimit.class)) {
                AccessLimit accessLimit = method.getAnnotation(AccessLimit.class);
                //获取注解中的参数 限制周期(秒)
                int seconds = accessLimit.seconds();
                //获取注解中的参数 规定周期内限制次数
                int maxCount = accessLimit.maxCount();
                String redisKey = generateKey(request);
                try {
                    Long count = redisCache.incrementValue(redisKey, 1L);
                    // 第一次访问
                    if (Objects.nonNull(count) && count == 1) {
                        redisCache.expire(redisKey, seconds, TimeUnit.SECONDS);
                    } else if (count > maxCount) {
                        WebUtils.renderString(response, JSON.toJSONString(Result.fail(StatusCodeEnum.TOO_MANY_REQUESTS.getCode(),accessLimit.msg())));
//                        log.warn(redisKey + "请求次数超过每" + seconds + "秒" + maxCount + "次");
                        result = false;
                    }
                } catch (RedisConnectionFailureException e) {
//                    log.error("redis错误: " + e.getMessage());
                    result = false;
                }
            }
        }
        return result;
    }

    /**
     * 生成限制的 key，可以根据需要自定义
     */
    private String generateKey(HttpServletRequest request) {
        String ip = "";
        String path = request.getRequestURI();
        String method = request.getMethod();
        return RedisConstant.ACCESS_LIMIT_PREFIX + ip + ":" + path + ":" + method;
    }

}
